/*
 * main.c
 *
 *  Created on: 2012-6-26
 *      Author: rendong
 */

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <getopt.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/resource.h>

#include "core/chat_types.h"
#include "core/chat_log.h"
#include "logic/chat_connection.h"

#include "test/hashtest.c"
#include "test/listtest.c"
#include "lib/md5.h"

void parse_arguments(int argc, char ** argv);
void chat_daemon();
void exit_handler(int sig);
void run_test(int test_type);

/**
 * main
 */
int main (int argc, char ** argv)
{
	struct sigaction sa;
	struct rlimit r;

	parse_arguments (argc, argv);

	if(getrlimit(RLIMIT_NOFILE,&r)<0){
		printf("get RLIMIT_NOFILE fail!\n");
		return EXIT_FAILURE;
	}

	if ((int)r.rlim_cur < cfg_maxclients){
		r.rlim_cur = r.rlim_max = cfg_maxclients + 10;

		if (setrlimit(RLIMIT_NOFILE, &r)){
			printf("setrlimit fail error:%d:%s\nmaxclients(%d) greater than max open files(%lu),pls use <ulimit -n number> to change!\n",
					errno, strerror(errno), cfg_maxclients, r.rlim_cur);
			return EXIT_FAILURE;
		}
	}

	if (cfg_is_daemon)
		chat_daemon();

	memset(&sa, 0, sizeof(struct sigaction));

	sa.sa_handler = SIG_IGN;
	sigaction(SIGPIPE, &sa, 0);

	sa.sa_handler = exit_handler;
	sigaction(SIGINT, &sa, 0);

	chat_start_chat_server();

	return EXIT_SUCCESS;
}

void exit_handler(int sig)
{
	exit(0);
}

/**
 * 后台运行
 */
void chat_daemon()
{
	int fd;

	switch (fork()){
	case -1:
		chat_log_error("daemon fork error\n");
		exit(1);
		break;
	case 0: // child
		break;
	default:// parent
		exit(0);
	}

	if (setsid() == -1){
		chat_log_error("daemon setsid() failed\n");
		exit(1);
	}

	umask(0);

	fd = open("/dev/null", O_RDWR);
	if (fd == -1) {
		chat_log_error("daemon open /dev/null fail\n");
		exit(1);
	}

	if (dup2(fd, STDIN_FILENO) == -1) {
		chat_log_error("daemon dup2 STDIN fail\n");
		exit(1);
	}

	if (dup2(fd, STDOUT_FILENO) == -1) {
		chat_log_error("daemon dup2 STDOUT fail\n");
		exit(1);
	}

	if (dup2(fd, STDERR_FILENO) == -1) {
		chat_log_error("daemon dup2 STDERR fail\n");
		exit(1);
	}

	if (fd > STDERR_FILENO) {
		if (close(fd) == -1) {
			chat_log_error("daemon close() fail\n");
			exit(1);
		}
	}
}


/**
 * 解析命令行参数
 */
void parse_arguments(int argc, char ** argv)
{
	char *l_opt_arg;
	struct option long_options[] = {
	{ "help",	0,	NULL,	'h'},
	{ "ip",	1,	NULL, 	'i'},
	{ "port",	1,	NULL,	'p'},
	{ "test",	1,	NULL,	't'},
	{ "secret",	1,	NULL,	's'},
	{ "daemon",	1,	NULL,	'd'},
	{ "log",	1,	NULL,	'l'},
	{ "detaillog",	1,	NULL,	'o'},
	{ "errorlog",	1,	NULL,	'e'},
	{  0,    0,    0,    0},
	};

	int c;
	while((c = getopt_long (argc, argv, "hi:p:t:dl:o:e:s:", long_options, NULL)) != -1)
	{
		switch (c)
		{
			case 'i':
				cfg_local_addr = optarg;
				break;
			case 'p':
				l_opt_arg = optarg;
				cfg_port = atoi(l_opt_arg);
				break;
			case 's':
				l_opt_arg = optarg;
				cfg_login_type = atoi(l_opt_arg);
				break;
			case 'd':
				cfg_is_daemon = 1;
				break;
			case 't':
				l_opt_arg = optarg;
				run_test(atoi(l_opt_arg));
				break;
			case 'l':
				cfg_log_fname = optarg;
				break;
			case 'e':
				cfg_errorlog_fname = optarg;
				break;
			case 'o':
				cfg_phplog_fname = optarg;
				break;
			case 'h':
			case '?':
				printf("Usage: %s [OPTION]...\n\
default ip=%s port=%d\n\n\
  -i, --ip=ip host                    server bind ip\n\
  -p, --port=socket port        server socket port\n\
  -d, --daemon                      daemon\n\
  -s, --secret                      secret type 0:default 1:md5\n\
  -l, --log                               chat log filename\n\
  -o, --detaillog                     chat detail log filename default=null\n\
  -e, --errorlog                      chat error log filename\n\
  -t, --test                             run test\n\
  -h, --help                            display this help and exit\n\n", argv[0], cfg_local_addr, cfg_port);
				exit(1);
				break;
		}
	}
}


void run_test(int test_type)
{
	printf("run test:%d\n", test_type);
	switch(test_type)
	{
	case 1:
		test_hash(1024);
		test_hash(10240);
		test_hash(102400);
		break;
	case 2:
		test_list(1024);
		test_list(10240);
		break;
	}

	exit(EXIT_SUCCESS);
}
